package main

import "fmt"

func main() {
	// goto 测试
	gotoFunction()
	// for 测试
	forFunction()
	// 函数返回值测试
	fmt.Println(functionName("吴彦祖", 12))
	// 函数指针传递测试
	a := 1
	add(&a) // &a 调用 a 的地址值
	fmt.Println(a)
	// switch 测试
	switchFunction("hello")
	// defer 测试
	deferFunction()
	// 函数当做参数传递 测试
	arr := []int{1, 2, 3, 4, 5}
	even := filter(arr, isEven)
	odd := filter(arr, isOdd)
	fmt.Println(even)
	fmt.Println(odd)
	// 变参函数测试
	spliceFunction("第一行", "第二行", "第三行")
}

// function
func functionName(input1 string, input2 int) (output1 string, output2 int) {
	input1 += "变了"
	input2++
	// 如果没有返回值，return 可以省略
	// return input1,input2
	output1 = "好好学习天天向上"
	output2 = 233
	// 直接 return 会返回函数一开始声明的返回值，可读性降低，官方不建议
	return
}

// 指针传递
func add(i *int) int {
	// 注意写法 *i
	*i++
	return *i
}

// goto 用法
func gotoFunction() {
	fmt.Println("gotoFunction:")
	i := 0
Here:
	fmt.Println("我是", i)
	i++
	if i < 10 {
		goto Here
	}
}

// for 用法
func forFunction() {
	fmt.Println("forFuction:")
	i := 0
	for i < 10 {
		fmt.Println(i)
		i++
	}
	for index := 20; index > 10; index-- {
		fmt.Println(index)
	}

	// for 配合 range 遍历 map
	tempMap := map[string]string{"a": "我是A", "b": "我是B"}
	for k, v := range tempMap {
		fmt.Print("key:", k)
		fmt.Println("\tvalue:", v)
	}

	fmt.Println("defer用法")
	for i := 0; i < 5; i++ {
		defer fmt.Printf("%d ", i)
	}
}

// switch 用法
func switchFunction(str string) {
	switch str {
	case "hello":
		fmt.Println("你输入了hello")
	case "b", "c":
		fmt.Println("你输入了b或者c")
		// go 没有 break,fallthrough 会强制执行后面的 case
		fallthrough
	default:
		fmt.Println("认不出来")
	}
}

// defer 用法 当函数执行到最后时，这些defer语句会按照逆序执行
// defer是采用后进先出模式
func deferFunction() {
	defer fmt.Println("first")
	defer fmt.Println("second")
	fmt.Println("third")
	for i := 0; i < 5; i++ {
		defer fmt.Println(i)
	}
}

// 函数当做参数传递
func isOdd(i int) bool {
	if i%2 == 0 {
		return false
	} else {
		return true
	}
}

func isEven(i int) bool {
	if i%2 == 0 {
		return true
	} else {
		return false
	}
}

// 声明一个函数类型
type f func(int) bool

func filter(arr []int, f2 f) (newArr []int) {
	for _, value := range arr {
		if f2(value) {
			newArr = append(newArr, value)
		}
	}
	return
}

// 变参函数
func spliceFunction(arr ...string) {
	for _, value := range arr {
		fmt.Println(value)
	}
}

//Panic和Recover
//参考  https://github.com/astaxie/build-web-application-with-golang/blob/master/zh/02.3.md
//Go没有像Java那样的异常机制，它不能抛出异常，而是使用了panic和recover机制。一定要记住，你应当把它作为最后的手段来使用，也就是说，你的代码中应当没有，或者很少有panic的东西。这是个强大的工具，请明智地使用它。那么，我们应该如何使用它呢？
//Panic
//是一个内建函数，可以中断原有的控制流程，进入一个panic状态中。
// 当函数F调用panic，函数F的执行被中断，但是F中的延迟函数会正常执行，然后F返回到调用它的地方。
// 在调用的地方，F的行为就像调用了panic。这一过程继续向上，直到发生panic的goroutine中所有调用的函数返回，此时程序退出。
// panic可以直接调用panic产生。也可以由运行时错误产生，例如访问越界的数组。
//Recover
//是一个内建的函数，可以让进入panic状态的goroutine恢复过来。
// recover仅在延迟函数中有效。在正常的执行过程中，调用recover会返回nil，并且没有其它任何效果。
// 如果当前的goroutine陷入panic状态，调用recover可以捕获到panic的输入值，并且恢复正常的执行。
